package com.wz.dhs.controller.login;

import cn.binarywang.wx.miniapp.api.WxMaService;
import cn.binarywang.wx.miniapp.bean.WxMaJscode2SessionResult;
import cn.binarywang.wx.miniapp.bean.WxMaPhoneNumberInfo;
import cn.binarywang.wx.miniapp.util.WxMaConfigHolder;
import com.wz.dhs.constant.RedisKeyConstant;
import com.wz.dhs.dto.user.LoginDTO;
import com.wz.dhs.dto.user.RegisterDTO;
import com.wz.dhs.exception.BusinessException;
import com.wz.dhs.model.UserContextHolder;
import com.wz.dhs.model.UserTokenCache;
import com.wz.dhs.model.common.Result;
import com.wz.dhs.po.user.SysUserEntity;
import com.wz.dhs.service.base.UserService;
import com.wz.dhs.utils.JWTTokenUtil;
import com.wz.dhs.utils.RedisUtils;
import com.wz.dhs.vo.login.Oauth2TokenVO;
import com.wz.dhs.vo.login.WxLoginResultVO;
import com.wz.dhs.vo.user.UserBaseInfoVO;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import me.chanjar.weixin.common.error.WxErrorException;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import javax.validation.Valid;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.util.Objects;
import java.util.concurrent.TimeUnit;

import static cn.hutool.jwt.JWTUtil.createToken;

/**
 * @param
 * @author xia
 * @Description: 登录相关
 * @date 2021/1/24
 */
@RestController
@Validated
@AllArgsConstructor
@RequestMapping("/user")
@Slf4j
@Api(tags = "登录相关")
public class LoginController {

    @Autowired
    private WxMaService wxMaService;

    @Autowired
    private UserService userService;

    @Autowired
    private ApplicationContext applicationContext;


    /**
     * 登陆接口
     */
    @ApiOperation("微信小程序登录")
    @GetMapping("/app/login")
    public Result<WxLoginResultVO> login(@ApiParam("授权code") @RequestParam("code") String code) {
        try {
            WxMaJscode2SessionResult session = wxMaService.getUserService().getSessionInfo(code);
            String openid = session.getOpenid();
            log.info("微信小程序登录获取openid:{}", openid);

            SysUserEntity user = userService.lambdaQuery()
                    .eq(SysUserEntity::getOpenid, openid)
                    .one();
            if (Objects.nonNull(user)) {
                //登录成功
                return Result.data(createToken(user));
            }
            //新用户
            return Result.data(new WxLoginResultVO(openid, false));
        } catch (WxErrorException e) {
            log.error("微信小程序登录失败:{}", e);
            throw new BusinessException("10090");
        } finally {
            WxMaConfigHolder.remove();//清理ThreadLocal
        }
    }

    @ApiOperation("获取用户信息接口")
    @GetMapping("/info")
    public Result<WxLoginResultVO> info(@RequestParam("openid") String openid, @ApiParam("授权code") @RequestParam("code") String code,
                                        @RequestParam("nickname") String nickname,
                                        @RequestParam(value = "avatarUrl",required = false) @ApiParam("头像URL") String avatarUrl) throws WxErrorException {

        // 解密用户信息
        WxMaPhoneNumberInfo phoneInfo = wxMaService.getUserService().getNewPhoneNoInfo(code);
        String phone = phoneInfo.getPhoneNumber();
        WxMaConfigHolder.remove();//清理ThreadLocal

        SysUserEntity user = userService.lambdaQuery()
                .eq(SysUserEntity::getPhone, phone)
                .one();
        if (Objects.isNull(user)) {
            //新用户注册
            userService.save(SysUserEntity.builder()
                    .phone(phone)
                    .username(phoneInfo.getWatermark().getAppid())
                    .openid(openid)
                    .username(nickname)
                    .avatar(avatarUrl)
                    .accountStatus(true).build());
            log.info("[小程序注册成功][{}]", phone);
            user = userService.lambdaQuery()
                    .eq(SysUserEntity::getOpenid, openid)
                    .one();
        }
        return Result.data(createToken(user));
    }

    @PostMapping("/login")
    @ApiOperation("用户登录")
    public Result<Oauth2TokenVO> login(@RequestBody @Valid LoginDTO param) {
        return Result.data(userService.login(param));
    }
    @ApiOperation("退出登录")
    @PostMapping("/logout")
    public Result<String> logout(HttpServletRequest request) {
        String token = request.getHeader("token");
        userService.logout(token);
        return Result.success("登出成功");
    }


    @ApiOperation("用户注册")
    @PostMapping("/register")
    public Result<String> userRegister(@RequestBody @Valid RegisterDTO param) {
        userService.userRegister(param);
        return Result.success("用户注册成功");
    }

    @PostMapping("/baseInfo")
    @ApiOperation("查看用户信息")
    public Result<UserBaseInfoVO> selectUserInfo() {
        SysUserEntity user = userService.getById(UserContextHolder.getUserId());
        UserBaseInfoVO baseInfo = new UserBaseInfoVO();
        baseInfo.setUserId(user.getId());
        baseInfo.setOpenid(user.getOpenid());
        baseInfo.setUsername(user.getUsername());
        baseInfo.setPhone(user.getPhone());
        baseInfo.setAvatar(user.getAvatar());
        if(Objects.nonNull(user.getVipExpireTime()) && user.getVipExpireTime().isAfter(LocalDateTime.now())){
            baseInfo.setVipExpireTime(user.getVipExpireTime());
        }
        return Result.data(baseInfo);
    }


    /**
     * 微信小程序登录成功组装参数
     * @param data
     * @return
     */
    private WxLoginResultVO createToken(SysUserEntity data) {
        WxLoginResultVO oauth2TokenVO = new WxLoginResultVO();
        String token = JWTTokenUtil.createAccessToken(data.getId());
        UserTokenCache user = new UserTokenCache();
        BeanUtils.copyProperties(data, user);
        user.setUserId(data.getId());
        String key = String.format(RedisKeyConstant.USER_TOKEN_PREFIX, token);
        // 将用户信息存入redis
        LocalDateTime expireTime = LocalDateTime.now().plusDays(15);
        RedisUtils.setValueWithExpire(key, user, TimeUnit.DAYS, 15L);

        oauth2TokenVO.setPhone(data.getPhone());
        oauth2TokenVO.setAvatar(data.getAvatar());
        oauth2TokenVO.setUserId(data.getId());
        oauth2TokenVO.setPhone(data.getPhone());
        oauth2TokenVO.setUsername(data.getUsername());
        oauth2TokenVO.setExpiresIn(expireTime.toInstant(ZoneOffset.ofHours(8)).toEpochMilli());
        oauth2TokenVO.setToken(token);
        oauth2TokenVO.setResult(true);
        return oauth2TokenVO;
    }



}
